package item;

import inutan.game.business.GameFlowContext;
import inutan.game.entity.UserInfo;
import inutan.game.entity.prop.BaseItemInfo;
import inutan.game.prop.OperatePropInterface;
import org.ricks.common.exception.ServerBootstrapException;
import org.ricks.orm.OrmContext;

import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.ToIntFunction;

public abstract class AbstractCurrencyOperate implements OperatePropInterface {
    private final int itemType;
    private final ToIntFunction<UserInfo> getter;
    private final BiConsumer<UserInfo, Integer> setter;

    protected AbstractCurrencyOperate(int itemType,
                                      ToIntFunction<UserInfo> getter,
                                      BiConsumer<UserInfo, Integer> setter) {
        this.itemType = itemType;
        this.getter = getter;
        this.setter = setter;
    }

    @Override
    public List<BaseItemInfo> props(GameFlowContext context) {
        int amount = getter.applyAsInt(loadUser(context));
        return List.of(new BaseItemInfo(itemType, itemType, amount));
    }

    @Override
    public void useProp(GameFlowContext context, List<BaseItemInfo> items) {
        modifyCurrency(context, -sumAmount(items));
    }

    @Override
    public List<BaseItemInfo> addProp(GameFlowContext context, List<BaseItemInfo> items) {
        modifyCurrency(context, sumAmount(items));
        return items;
    }

    @Override
    public boolean checkItemNum(GameFlowContext context, List<BaseItemInfo> items) {
        return getter.applyAsInt(loadUser(context)) >= sumAmount(items);
    }

    private UserInfo loadUser(GameFlowContext context) {
        return OrmContext.me().uniqueCacheLoad(UserInfo.class, context.getUserId())
                .orElseThrow(() -> new ServerBootstrapException("用户不存在"));
    }

    private void modifyCurrency(GameFlowContext context, int delta) {
        UserInfo user = loadUser(context);
        setter.accept(user, getter.applyAsInt(user) + delta);
        OrmContext.me().update(user);
    }

    private static int sumAmount(List<BaseItemInfo> items) {
        return items.stream().mapToInt(BaseItemInfo::getCount).sum();
    }
}
